using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MKDS_Course_Editor.NSBTP
{
    public partial class NSBPT_Edit : Form
    {
        string filename;
        string filename2;
        public NSBPT_Edit(string fname, string nsbtx)
        {
            filename = fname;
            filename2 = nsbtx;
            InitializeComponent();
            toolStrip1.Renderer = new TestStripRenderer();
            listViewFrameControl1.HScrollbar = hScrollBar1;
            toolStrip3.Renderer = new TestStripRenderer();
        }
        public NSBPT_Edit(NSBTP.NSBTP_File fname, string nsbtx, string name)
        {
            tp = fname;
            filename = name;
            filename2 = nsbtx;
            InitializeComponent();
            toolStrip1.Renderer = new TestStripRenderer();
            listViewFrameControl1.HScrollbar = hScrollBar1;
            toolStrip3.Renderer = new TestStripRenderer();
            wizard = true;
        }
        NSBTP.NSBTP_File tp;
        bool wizard = false;
        NSBTX.nsbtx_.NSBTX_File tx;
        int selectedanim = 0;
        private void NSBPT_Edit_Load(object sender, EventArgs e)
        {
            if (!wizard)
            {
                tp = NSBTP.Read(filename);
            }
            NSBTX.nsbtx_ n = new NSBTX.nsbtx_(filename2, false);
            n.load();
            tx = n.nsbtx;
            toolStripDropDownButton1.Text = tp.MPT.names[0];
            for (int i = 0; i < tp.MPT.names.Length; i++)
            {
                toolStripDropDownButton1.DropDownItems.Add(tp.MPT.names[i], null, OnAnimChange);
            }
            for (int i = 0; i < tp.AnimData[selectedanim].KeyFrames.Length; i++)
            {
                imageList1.Images.Add(MakeImage(tp.AnimData[selectedanim].KeyFrames[i].texName, tp.AnimData[selectedanim].KeyFrames[i].palName));
                listViewFrameControl1.Items.Add(tp.AnimData[selectedanim].KeyFrames[i].texName, i);
            }
            if (listViewFrameControl1.Width / 68 <= listViewFrameControl1.Items.Count - 1)
            {
                hScrollBar1.Minimum = 0;
                hScrollBar1.Maximum = (listViewFrameControl1.Items.Count - listViewFrameControl1.Width / 68) * 68;
                hScrollBar1.Enabled = true;
            }
            else
            {
                hScrollBar1.Enabled = false;
            }
        }
        private void OnAnimChange(object sender, EventArgs e)
        {
            selectedanim = tp.MPT.names.ToList().IndexOf((sender as ToolStripDropDownItem).Text);
            toolStripDropDownButton1.Text = tp.MPT.names[selectedanim];
            listViewFrameControl1.Items.Clear();
            imageList1.Images.Clear();
            for (int i = 0; i < tp.AnimData[selectedanim].KeyFrames.Length; i++)
            {
                imageList1.Images.Add(MakeImage(tp.AnimData[selectedanim].KeyFrames[i].texName, tp.AnimData[selectedanim].KeyFrames[i].palName));
                listViewFrameControl1.Items.Add(tp.AnimData[selectedanim].KeyFrames[i].texName, i);
            }
            if (listViewFrameControl1.Width / 68 <= listViewFrameControl1.Items.Count - 1)
            {
                hScrollBar1.Minimum = 0;
                hScrollBar1.Maximum = (listViewFrameControl1.Items.Count - listViewFrameControl1.Width / 68) * 68;
                hScrollBar1.Enabled = true;
            }
            else
            {
                hScrollBar1.Enabled = false;
            }
            timer1.Enabled = false;
        }
        private Image MakeImage(string texname, string palname)
        {
            int idex1 = tx.TexInfo.names.ToList().IndexOf(texname);
            int idex2 = tx.PalInfo.names.ToList().IndexOf(palname);
            Bitmap b = new Bitmap(tx.TexInfo.infoBlock.TexInfo[idex1].width, tx.TexInfo.infoBlock.TexInfo[idex1].height);
            int pixelnum = b.Height * b.Width;
            try
            {
                switch (tx.TexInfo.infoBlock.TexInfo[idex1].format)
                {
                    case 1:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            int index = tx.TexInfo.infoBlock.TexInfo[idex1].Image[j] & 0x1f;
                            int alpha = (tx.TexInfo.infoBlock.TexInfo[idex1].Image[j] >> 5);
                            alpha = ((alpha * 4) + (alpha / 2)) * 8;
                            Color c = Color.FromArgb(alpha, tx.PalInfo.infoBlock.PalInfo[idex2].pal[index]);
                            b.SetPixel(j - ((j / (tx.TexInfo.infoBlock.TexInfo[idex1].width)) * (tx.TexInfo.infoBlock.TexInfo[idex1].width)), j / (tx.TexInfo.infoBlock.TexInfo[idex1].width), c);
                        }
                        break;
                    case 2:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            uint index = tx.TexInfo.infoBlock.TexInfo[idex1].Image[j / 4];
                            index = (index >> ((j % 4) << 1)) & 3;
                            b.SetPixel(j - ((j / (tx.TexInfo.infoBlock.TexInfo[idex1].width)) * (tx.TexInfo.infoBlock.TexInfo[idex1].width)), j / (tx.TexInfo.infoBlock.TexInfo[idex1].width), tx.PalInfo.infoBlock.PalInfo[idex2].pal[index]);
                        }
                        if (tx.TexInfo.infoBlock.TexInfo[idex1].color0 == 1) { b.MakeTransparent(tx.PalInfo.infoBlock.PalInfo[idex2].pal[0]); }
                        break;
                    case 3:
                        //sp.PLTO[idex1].Pal[sp.PLTO[idex1].Unknown] = Color.Transparent; // made palette entry 0 transparent
                        for (int j = 0; j < pixelnum; j++)
                        {
                            uint index = tx.TexInfo.infoBlock.TexInfo[idex1].Image[j / 2];
                            index = (index >> ((j % 2) << 2)) & 0x0f;
                            b.SetPixel(j - ((j / (tx.TexInfo.infoBlock.TexInfo[idex1].width)) * (tx.TexInfo.infoBlock.TexInfo[idex1].width)), j / (tx.TexInfo.infoBlock.TexInfo[idex1].width), tx.PalInfo.infoBlock.PalInfo[idex2].pal[index]);
                        }
                        if (tx.TexInfo.infoBlock.TexInfo[idex1].color0 == 1) { b.MakeTransparent(tx.PalInfo.infoBlock.PalInfo[idex2].pal[0]); }
                        break;
                    case 4:
                        //if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
                        for (int j = 0; j < pixelnum; j++)
                        {
                            byte index = tx.TexInfo.infoBlock.TexInfo[idex1].Image[j];
                            b.SetPixel(j - ((j / (tx.TexInfo.infoBlock.TexInfo[idex1].width)) * (tx.TexInfo.infoBlock.TexInfo[idex1].width)), j / (tx.TexInfo.infoBlock.TexInfo[idex1].width), tx.PalInfo.infoBlock.PalInfo[idex2].pal[index]);
                        }
                        if (tx.TexInfo.infoBlock.TexInfo[idex1].color0 == 1) { b.MakeTransparent(tx.PalInfo.infoBlock.PalInfo[idex2].pal[0]); }
                        break;
                    case 5:
                        convert_4x4texel_b(tx.TexInfo.infoBlock.TexInfo[idex1].Image, tx.TexInfo.infoBlock.TexInfo[idex1].width, tx.TexInfo.infoBlock.TexInfo[idex1].height, tx.TexInfo.infoBlock.TexInfo[idex1].spData, tx.PalInfo.infoBlock.PalInfo[idex2].pal, b);
                        break;
                    case 6:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            int index = tx.TexInfo.infoBlock.TexInfo[idex1].Image[j] & 0x7;
                            int alpha = (tx.TexInfo.infoBlock.TexInfo[idex1].Image[j] >> 3);// & 0x1f;
                            alpha *= 8;
                            Color c = Color.FromArgb(alpha, tx.PalInfo.infoBlock.PalInfo[idex2].pal[index]);
                            b.SetPixel(j - ((j / (tx.TexInfo.infoBlock.TexInfo[idex1].width)) * (tx.TexInfo.infoBlock.TexInfo[idex1].width)), j / (tx.TexInfo.infoBlock.TexInfo[idex1].width), c);
                        }
                        break;
                    case 7:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            UInt16 p = (ushort)(tx.TexInfo.infoBlock.TexInfo[idex1].Image[j * 2] + (tx.TexInfo.infoBlock.TexInfo[idex1].Image[j * 2 + 1] << 8));
                            Color c = Color.FromArgb((((p & 0x8000) != 0) ? 0xff : 0), (((p >> 0) & 0x1f) << 3), (((p >> 5) & 0x1f) << 3), (((p >> 10) & 0x1f) << 3));
                            b.SetPixel(j - ((j / (tx.TexInfo.infoBlock.TexInfo[idex1].width)) * (tx.TexInfo.infoBlock.TexInfo[idex1].width)), j / (tx.TexInfo.infoBlock.TexInfo[idex1].width), c);
                        }
                        break;
                }
            }
            catch
            {
                goto end2;
            }
        end2:
            return b;
        }
        /// <summary>
        /// Convert texel.
        /// </summary>
        private bool convert_4x4texel(uint[] tex, int width, int height, UInt16[] data, Color[] pal, Bitmap rgbaOut)
        {
            int w = width / 4;
            int h = height / 4;

            // traverse 'w x h blocks' of 4x4-texel
            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    int index = y * w + x;
                    UInt32 t = tex[index];
                    UInt16 d = data[index];
                    UInt16 addr = (ushort)(d & 0x3fff);
                    UInt16 mode = (ushort)((d >> 14) & 3);

                    // traverse every texel in the 4x4 texels
                    for (int r = 0; r < 4; r++)
                        for (int c = 0; c < 4; c++)
                        {
                            int texel = (int)((t >> ((r * 4 + c) * 2)) & 3);
                            Color pixel = rgbaOut.GetPixel((x * 4 + c), (y * 4 + r));

                            switch (mode)
                            {
                                case 0:
                                    pixel = pal[(addr << 1) + texel];
                                    if (texel == 3) pixel = Color.Transparent; // make it transparent, alpha = 0
                                    break;
                                case 2:
                                    pixel = pal[(addr << 1) + texel];
                                    break;
                                case 1:
                                    switch (texel)
                                    {
                                        case 0:
                                        case 1:
                                            pixel = pal[(addr << 1) + texel];
                                            break;
                                        case 2:
                                            pixel = Color.FromArgb(0xff, (int)((pal[(addr << 1)].R + pal[(addr << 1) + 1].R) / 2L), (int)((pal[(addr << 1)].G + pal[(addr << 1) + 1].G) / 2L), (int)((pal[(addr << 1)].B + pal[(addr << 1) + 1].B) / 2L));
                                            break;
                                        case 3:
                                            pixel = Color.Transparent; // make it transparent, alpha = 0
                                            break;
                                    }
                                    break;
                                case 3:
                                    switch (texel)
                                    {
                                        case 0:
                                        case 1:
                                            pixel = pal[(addr << 1) + texel];
                                            break;
                                        case 2:
                                            pixel = Color.FromArgb(0xff, (int)((pal[(addr << 1)].R * 5L + pal[(addr << 1) + 1].R * 3L) / 8), (int)((pal[(addr << 1)].G * 5L + pal[(addr << 1) + 1].G * 3L) / 8), (int)((pal[(addr << 1)].B * 5L + pal[(addr << 1) + 1].B * 3L) / 8));
                                            break;
                                        case 3:
                                            pixel = Color.FromArgb(0xff, (int)((pal[(addr << 1)].R * 3L + pal[(addr << 1) + 1].R * 5L) / 8), (int)((pal[(addr << 1)].G * 3L + pal[(addr << 1) + 1].G * 5L) / 8), (int)((pal[(addr << 1)].B * 3L + pal[(addr << 1) + 1].B * 5L) / 8));
                                            break;
                                    }
                                    break;
                            }
                            rgbaOut.SetPixel((x * 4 + c), (y * 4 + r), pixel);
                            //rgbaOut[(y * 4 + r) * width + (x * 4 + c)] = pixel;
                        }
                }
            return true;
        }

        /// <summary>
        /// Convert texel (wrapper for type safety issues).
        /// </summary>
        private void convert_4x4texel_b(byte[] tex, int width, int height, byte[] data, Color[] pal, Bitmap rgbaOut)
        {
            var list1 = new List<uint>();
            for (int i = 0; i < (tex.Length + 1) / 4; ++i)
                list1.Add(LibNDSFormats.Utils.Read4BytesAsUInt32(tex, i * 4));

            var list2 = new List<UInt16>();
            for (int i = 0; i < (data.Length + 1) / 2; ++i)
                list2.Add(LibNDSFormats.Utils.Read2BytesAsUInt16(data, i * 2));
            var b = convert_4x4texel(list1.ToArray(), width, height, list2.ToArray(), pal, rgbaOut);
        }
        public class TestStripRenderer : ToolStripSystemRenderer
        {
            protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
            {
                e.Graphics.FillRectangle(new SolidBrush(e.BackColor), 0, 0, e.ToolStrip.Width, e.ToolStrip.Height);
            }
            protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
            {
            }
        }

        private void listViewFrameControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listViewFrameControl1.SelectedIndices.Count != 0)
            {
                Image i = MakeImage(tp.AnimData[selectedanim].KeyFrames[listViewFrameControl1.SelectedIndices[0]].texName, tp.AnimData[selectedanim].KeyFrames[listViewFrameControl1.SelectedIndices[0]].palName);
                pictureBox1.Image = i;
                if (!timer1.Enabled)
                {
                    FrameProperty p = new FrameProperty();
                    p.Start = tp.AnimData[selectedanim].KeyFrames[listViewFrameControl1.SelectedIndices[0]].Start;
                    if (listViewFrameControl1.SelectedIndices[0] != tp.AnimData[selectedanim].KeyFrames.Length - 1)
                    {
                        p.Duration = tp.AnimData[selectedanim].KeyFrames[listViewFrameControl1.SelectedIndices[0] + 1].Start - tp.AnimData[selectedanim].KeyFrames[listViewFrameControl1.SelectedIndices[0]].Start;
                    }
                    else
                    {
                        p.Duration = tp.MPT.NoFrames - tp.AnimData[selectedanim].KeyFrames[listViewFrameControl1.SelectedIndices[0]].Start;
                    }
                    p.Img = i;
                    propertyGrid1.SelectedObject = p;
                }
                else
                {
                    propertyGrid1.SelectedObject = null;
                }
            }
            else
            {
                pictureBox1.Image = null;
                if (!timer1.Enabled)
                {
                    AnimProperty p = new AnimProperty();
                    p.numFrame = tp.MPT.infoBlock.Data[selectedanim].KeyFrames;
                    p.Speed = tp.MPT.infoBlock.Data[selectedanim].Unknown1>>4;
                    propertyGrid1.SelectedObject = p;
                }
            }
        }

        private void listViewFrameControl1_Resize(object sender, EventArgs e)
        {
            if (listViewFrameControl1.Width / 68 <= listViewFrameControl1.Items.Count - 1)
            {
                hScrollBar1.Minimum = 0;
                hScrollBar1.Maximum = (listViewFrameControl1.Items.Count - listViewFrameControl1.Width / 68) * 68;
                hScrollBar1.Enabled = true;
            }
            else
            {
                hScrollBar1.Enabled = false;
            }
        }
        private void timer1_Tick(object sender, EventArgs e)
        {

        }
        private void toolStripButton4_Click(object sender, EventArgs e)
        {
            //timer1.Enabled = !timer1.Enabled;
            if ((sender as ToolStripButton).Checked)
            {
                backgroundWorker1.RunWorkerAsync();
            }
            else
            {
                backgroundWorker1.CancelAsync();
            }
        }
        private class AnimProperty
        {
            [Description("The speed of this animation.")]
            public float Speed { get; set; }
            public int numFrame;
            [Description("The number of Keyframes."), DisplayName("Number of Keyframes")]
            public int Numframe { get { return numFrame; } }
        }
        private class FrameProperty
        {
            [Description("The time the frame is displayed.")]
            public int Duration { get; set; }
            [Description("The texture."), DisplayName("Texture")]
            public Image Img { get; set; }
            [Description("The time when the frame starts to be viewed.")]
            public int Start { get; set; }
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            int frame = 0;
            int nr = 0;
            int frame_ = 0;
            while (!(sender as BackgroundWorker).CancellationPending)
            {
                (sender as BackgroundWorker).ReportProgress(frame_);
                if (true)
                {
                    nr = 0;
                    if (frame == tp.MPT.NoFrames - 1)
                    {
                        frame = 0;
                        frame_ = 0;
                    }
                    else
                    {
                        frame++;
                        if (tp.AnimData[selectedanim].KeyFrames.Length != frame_ + 1)
                        {
                            if (frame == tp.AnimData[selectedanim].KeyFrames[frame_ + 1].Start)
                            {
                                frame_++;
                            }
                        }
                    }
                }
                else
                {
                    nr++;//= (float)p.MPT.infoBlock.Data[new List<string>(p.MPT.names).IndexOf(mat.MaterialName)].Unknown1 / 4096f;
                }
                System.Threading.Thread.Sleep(100);//(int)(((tp.MPT.infoBlock.Data[selectedanim].Unknown1) >> 4)/1024f*400f));
            }
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {

            if (listViewFrameControl1.SelectedIndices.Count == 0 || listViewFrameControl1.SelectedIndices[0] != e.ProgressPercentage)
            {
                listViewFrameControl1.SelectedIndices.Clear();
                listViewFrameControl1.SelectedIndices.Add(e.ProgressPercentage);
            }
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

        }
    }
    public class ListViewFrameItem : ListViewItem
    {
        public override void EnsureVisible()
        {
            base.EnsureVisible();
        }
    }
    public class ListViewFrameControl : ListView
    {
        public ListViewFrameControl()
        {
            this.View = System.Windows.Forms.View.Tile;
            this.TileSize = new Size(2, 2);
        }
        protected override bool DoubleBuffered
        {
            get
            {
                return true;
            }
            set
            {
                base.DoubleBuffered = value;
            }
        }
        protected override void OnLostFocus(EventArgs e)
        {
            //base.OnLostFocus(e);
            Refresh();
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
        }
        public event EventHandler Resized;
        protected override void OnResize(EventArgs e)
        {
            //ResizeRedraw = false;
            //base.OnResize(e);
            this.MaximumSize = new Size(this.Width, this.Height);
            this.MinimumSize = new Size(this.Width, this.Height);
            this.SetBounds(this.Location.X, this.Location.Y, this.Width + this.Items.Count * 100, 82);
            this.MaximumSize = new Size(0, 0);
            this.MinimumSize = new Size(0, 0);

            if (this.Resized != null)
                this.Resized(this, new EventArgs());
            Refresh();
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            //base.OnMouseUp(e);
            if (SelectedIndices.Count != 0)
            {
                int lastselected = SelectedIndices[0];
                if (e.Y <= 80 && ((e.X + offset) / 69) < Items.Count)
                {
                    SelectedIndices.Clear();
                    SelectedIndices.Add(((e.X + offset) / 69));
                    //RedrawItems((e.X / 69), (e.X / 69), false);
                    this.Refresh();
                }
                //RedrawItems(lastselected, lastselected, false);
            }
            else
            {
                if (e.Y <= 80 && ((e.X + offset) / 69) < Items.Count)
                {
                    SelectedIndices.Add(((e.X + offset) / 69));
                    //RedrawItems((e.X / 69), (e.X / 69), false);
                    this.Refresh();
                }
            }
        }
        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            base.OnPaintBackground(pevent);
        }
        public HScrollBar HScrollbar
        {
            set
            {
                value.Scroll += new ScrollEventHandler(value_Scroll);
            }
        }
        private int offset;
        void value_Scroll(object sender, ScrollEventArgs e)
        {
            offset = e.NewValue;
            this.Refresh();
        }
        public override Color BackColor
        {
            get
            {
                return Color.FromArgb(237, 237, 237);
            }
            set
            {
                base.BackColor = value;
            }
        }
        public event EventHandler idexChange;
        protected override void OnSelectedIndexChanged(EventArgs e)
        {
            //base.OnSelectedIndexChanged(e);
            if (this.idexChange != null)
                this.idexChange(this, new EventArgs());
            this.Refresh();
        }
        protected override void OnDrawItem(DrawListViewItemEventArgs e)
        {
            //base.OnDrawItem(e);
            Color outline;
            //if (e.ItemIndex)
            outline = Color.FromArgb(160, 160, 160);
            e.Graphics.DrawLine(new Pen(outline), 2, 0, Width - 2, 0);
            e.Graphics.DrawLine(new Pen(outline), 2, 81, Width - 2, 81);
            e.Graphics.TranslateTransform(e.Item.Index * 69 + 2 - offset, 1);
            Color BG = Color.FromArgb(237, 237, 237);
            Color bg = BG;
            outline = Color.FromArgb(200, 200, 200);
            Color border = Color.FromArgb(160, 160, 160);
            Color text = Color.FromArgb(30, 30, 30);
            Color SELECTED = Color.FromArgb(51, 153, 255);
            SolidBrush b = new SolidBrush(Color.Black);
            if ((e.State & ListViewItemStates.Selected) != 0)
            {
                bg = SELECTED;
                outline = Color.White;
                text = Color.White;
            }
            b.Color = bg;
            e.Graphics.FillRectangle(b, 0, 0, 69, 80 - 1);
            int width = 69 - 2;
            b.Color = Color.FromArgb(160, 160, 160);
            e.Graphics.DrawLine(new Pen(b), 69 - 1, 0, width + 1, 80);
            int size = 4;
            b.Color = outline;
            e.Graphics.DrawRectangle(new Pen(b), size, size, width - size * 2, width - size * 2);
            size = 7;
            e.Graphics.DrawImage(drawGrid(4, 4, width - size * 2, width - size * 2), size + 1, size + 1);
            try
            {
                e.Graphics.DrawImage(e.Item.ImageList.Images[e.Item.ImageIndex], size + 1, size + 1);
            }
            catch { }
            String num = e.Item.Index.ToString();//(this.Parent.Controls.IndexOf(this) + 1).ToString();// t;//(new StringBuilder()).Append("").Append(getIndex() + 1).toString();
            int numWidth = num.Length * 5 + 7;
            int txtWidth = e.Item.Text.Length * 5 + 7;
            b.Color = BG;
            e.Graphics.FillRectangle(b, size, size, numWidth, 14);
            b.Color = border;
            e.Graphics.DrawRectangle(new Pen(b), size, size, width - size * 2, width - size * 2);
            e.Graphics.DrawRectangle(new Pen(b), size, size, numWidth, 14);
            b.Color = Color.FromArgb(100, 100, 100);
            e.Graphics.DrawString(num, new Font(new FontFamily("Tahoma"), 9), b, size, size /*+ 11*/);
            b.Color = text;
            e.Graphics.DrawString(e.Item.Text, new Font(new FontFamily("Tahoma"), 9), b, /*size + 2*/ (69f / 2f) - (txtWidth / 2f), /*size +*/ width - 4/* + 1*/);
        }
        private Image drawGrid(int tw, int th, int width, int height)
        {
            Image grid = new Bitmap(width, height);
            Color COLOR_BG = Color.FromArgb(255, 255, 255);
            Color COLOR_GRID = Color.FromArgb(204, 204, 204);

            using (Graphics g = Graphics.FromImage(grid))
            {
                g.FillRectangle(new SolidBrush(COLOR_BG), 0, 0, width, height);
                int cols = (int)Math.Ceiling((double)width / (double)tw);
                int rows = (int)Math.Ceiling((double)height / (double)th);
                for (int y = 0; y < rows; y++)
                {
                    for (int x = 0; x < cols; x++)
                    {
                        bool even = x % 2 == 1 && y % 2 == 0;
                        bool odd = x % 2 == 0 && y % 2 == 1;
                        if (even || odd)
                            g.FillRectangle(new SolidBrush(COLOR_GRID), x * tw, y * th, tw, th);
                    }

                }
            }
            return grid;
        }
    }
}
